<?php
using("Utils_HashMap");
using("Utils_Resource_Exception");
using("Resources_Catalog");

define('RESOURCE_EXTENSION', '.resource');
define('RESOURCE_VALUE_DELIMITER', '=');
define('RESOURCE_COMMENT_DELIMITER', "#");
/**
 * Managers provide an interface for access to properties files.  
 * 
 * <p>A properties file should be of the form: key=value.  Managers load 
 * the properties files and allow the values to be accessed via the getString 
 * method and their keys.  Properties files can also have comments.  Comments 
 * will include the special character assigned to the COMMENT_DELIMITER constant.  
 * Any line which begins with the comment delimiter will be ignored.
 * 
 * <p>Note that the properties files should be placed in the directory defined
 * by RESOURCE_PATH and have the extension defined by RESOURCE_EXTENSION.  
 * Also be sure to enable the web server to read the files.  In the event
 * that the resource file is not found the constructor will throw an exception.
 * 
 * TODO replace strings with resources
 *
 * @see Utils_HashMap
 * @package junction.utils.resource
 * @author Alexander Schearer <aas11@duke.edu>
 */
class Utils_Resource_Manager implements IteratorAggregate {
	
	/**
	 * Hashmap to store the resources
	 *
	 * @var Utils_HashMmap
	 */
	private $_resources;
	
	/**
	 * File extension
	 * 
	 * <p>This should be overridden by children in the event that
	 * a different file extension is desired.
	 *
	 * @var String
	 */
	protected $_type = RESOURCE_EXTENSION;
	
	protected $_comment = RESOURCE_COMMENT_DELIMITER;
	
	protected $_delimiter = RESOURCE_VALUE_DELIMITER;
	
	/**
	 * Construct an instance of the manager class.
	 * 
	 * <p>Take an instance of the owner class or a string and derive
	 * the path to the properties file.  The properties file should
	 * be present in the RESOURCE_PATH directory.
	 * <p>In the event that the properties file is not found then
	 * an exception is thrown.
	 *
	 * @throws Utils_Exceptions_Resource
	 * 
	 * @param Object $class
	 */
	public function __construct($class)
	{
		try {
			$this->_resources = $this->gatherResources($this->getClassname($class));
		} catch (Exception $e) {
			throw new Utils_Resource_Exception($e->getMessage());
		}
	}
	
	/**
	 * Retrieve a string which is associated with the given key.
	 *
	 * @param String $key
	 * @return String
	 */
	public function getString($key)
	{
		return $this->_resources->get($key);
	}
	/**
	 * Retrieve an iterator which will loop through the keys of the resources file and return them.  This 
	 * allows another class to iterate over all the contents of a managed file without having to know the
	 * keys explicitly.
	 *
	 * @return Iterator
	 */
	public function getIterator()
	{
		return $this->_resources->getIterator();
	}
	
	/**
	 * Open up the properties file and read its contents into an array.  Then attempt to parse the data into
	 * a proper structure for use by the manager.
	 *
	 * @param String $file
	 * @return Hashmap
	 */
	private function gatherResources($file)
	{
		try {
			$path = Resources_Catalog::fetch($file . $this->_type);
			if (!file_exists($path) || is_readable($$path))
				throw new Exception("Unable to read file: " . $file);
			return $this->parse(file($path));
		} catch (Exception $e) {
			throw new Utils_Resource_Exception($e->getMessage());
		}
	}
	
	/**
	 * Parse a string of data found in the properties files.  Data in the properties file should be be stored in the format
	 * key=value
	 * This will then be turned into a hash which is accessible through the interface.
	 *
	 * @param array $data
	 * @return Hashmap
	 */
	private function parse($data)
	{
		$result = new Utils_HashMap();
		foreach ($data as $line)
		{
			if (substr($line, 0, 1) != $this->_comment)
			{
				$tmp = explode($this->_delimiter, $line);
				$result->put($tmp[0], trim($tmp[1]));
			}
		}
		return $result;
	}
	
	/**
	 * Retrieve the classname of the passed class
	 * 
	 * <p>The passed class can be a string in which case
	 * it will be used as the classname.
	 *
	 * @param Object $class
	 * @return String
	 */
	private function getClassname($class)
	{
		return (is_string($class)) ? $class : get_class($class);
	}
}
?>